From: Jasper St. Pierre Date: Wed, 24 Aug 2011 17:08:34 +0000 (-0400) Subject: extensionSystem: Add install-from-HTTP capability X-Git-Tag: archive/raspbian/50.5-1+rpi1~1^2~1013^2^2~7914 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=d8a98e5467ca59a8203229fc10c9e5ca16158312;p=gnome-shell.git extensionSystem: Add install-from-HTTP capability This adds a new DBus method: InstallExtensionRemote(uuid : s, url : s) Pass it the UUID of an extension and the URL of a manifest file: the same as a metadata.json, but with a special key, '__installer', which is an HTTP location that points to an zip file containing the extension. The Shell will download and use it to install the extension. In the future, the manifest file may be used to automatically detect and install updates. https://bugzilla.gnome.org/show_bug.cgi?id=654770 --- diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js index 6bd6b9177..8907a8ee8 100644 --- a/js/ui/extensionSystem.js +++ b/js/ui/extensionSystem.js @@ -7,6 +7,7 @@ const GLib = imports.gi.GLib; const Gio = imports.gi.Gio; const St = imports.gi.St; const Shell = imports.gi.Shell; +const Soup = imports.gi.Soup; const Config = imports.misc.config; @@ -26,6 +27,15 @@ const ExtensionType = { PER_USER: 2 }; +const _httpSession = new Soup.SessionAsync(); + +// The unfortunate state of gjs, gobject-introspection and libsoup +// means that I have to do a hack to add a feature. +// See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context. + +if (Soup.Session.prototype.add_feature != null) + Soup.Session.prototype.add_feature.call(_httpSession, new Soup.ProxyResolverDefault()); + // Maps uuid -> metadata object const extensionMeta = {}; // Maps uuid -> importer object (extension directory tree) @@ -81,6 +91,79 @@ function versionCheck(required, current) { return false; } +function installExtensionFromManifestURL(uuid, url) { + _httpSession.queue_message( + Soup.Message.new('GET', url), + function(session, message) { + if (message.status_code != Soup.KnownStatusCode.OK) { + logExtensionError(uuid, 'downloading manifest: ' + message.status_code.toString()); + return; + } + + let manifest; + try { + manifest = JSON.parse(message.response_body.data); + } catch (e) { + logExtensionError(uuid, 'parsing: ' + e.toString()); + return; + } + + if (uuid != manifest['uuid']) { + logExtensionError(uuid, 'manifest: manifest uuids do not match'); + return; + } + + installExtensionFromManifest(manifest, meta); + }); +} + +function installExtensionFromManifest(manifest, meta) { + let uuid = manifest['uuid']; + let name = manifest['name']; + + let url = manifest['__installer']; + _httpSession.queue_message(Soup.Message.new('GET', url), + function(session, message) { + gotExtensionZipFile(session, message, uuid); + }); +} + +function gotExtensionZipFile(session, message, uuid) { + if (message.status_code != Soup.KnownStatusCode.OK) { + logExtensionError(uuid, 'downloading extension: ' + message.status_code); + return; + } + + // FIXME: use a GFile mkstemp-type method once one exists + let fd, tmpzip; + try { + [fd, tmpzip] = GLib.file_open_tmp('XXXXXX.shell-extension.zip'); + } catch (e) { + logExtensionError(uuid, 'tempfile: ' + e.toString()); + return; + } + + let stream = new Gio.UnixOutputStream({ fd: fd }); + let dir = userExtensionsDir.get_child(uuid); + Shell.write_soup_message_to_stream(stream, message); + stream.close(null); + let [success, pid] = GLib.spawn_async(null, + ['unzip', '-uod', dir.get_path(), '--', tmpzip], + null, + GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, + null); + + if (!success) { + logExtensionError(uuid, 'extract: could not extract'); + return; + } + + GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function(pid, status) { + GLib.spawn_close_pid(pid); + loadExtension(dir, true, ExtensionType.PER_USER); + }); +} + function disableExtension(uuid) { let meta = extensionMeta[uuid]; if (!meta) diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js index ae679ad52..07f2881b9 100644 --- a/js/ui/shellDBus.js +++ b/js/ui/shellDBus.js @@ -43,6 +43,10 @@ const GnomeShellIface = { { name: 'DisableExtension', inSignature: 's', outSignature: '' + }, + { name: 'InstallRemoteExtension', + inSignature: 's', + outSignature: '' } ], signals: [], @@ -166,6 +170,10 @@ GnomeShell.prototype = { global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions); }, + InstallRemoteExtension: function(uuid, url) { + ExtensionSystem.installExtensionFromManifestURL(uuid, url); + }, + get OverviewActive() { return Main.overview.visible; },